local skynet = require "skynet"
require "skynet.manager"    -- import skynet.register
local socket = require "socket"
local cjson = require "cjson"
local print_t = require "print_r"

local index = 1
local d_index = 1
local l_host
local l_from
local l_on = 0

local command = {}

local g_set = {}

local testset = nil

local c_socket = nil
--[[
sprintf(buff, "1:%0.8x%0.8x%0.8x:%u:%u:%0.2d:%0.2d", CpuID[0],CpuID[1],CpuID[2],sendIndex,RecvIndex,switch1,switch2);
1:


--]]
function string_split(s)  
    local fields = {}  
    local pattern = "([^:]+)"  
    local index = 1
    string.gsub(s, pattern, function (c) 
                            fields[index] = c 
                            index = index + 1
                            end)  
    return fields
end  


function recv_data(s, from)
	local field = string_split(s)
	skynet.error("recv_data:",field[1],field[2],field[3],field[4])

    if  string.len(field[2]) ~= 24 then
        skynet.error("recv_data: find error field2", field[2], string.len(field[2]))
        return nil
    end

    local protype = tonumber(field[1])

    if protype ~= 1 and protype ~= 2 then
        skynet.error("recv_data: find error field1 ", protype)
        return nil
    end
    local sett = g_set[field[2]]

    if sett == nil and protype == 1 then
        g_set[field[2]] = {}
        sett = g_set[field[2]] 
        sett.error  = 0
        sett.recv_i = 0
        sett.pre_check_time = 0
        sett.send_i = 0
        sett.recv_send_i = 0
        sett.last_recvtime = 0
        sett.last_ready_time = 0         --下次又能使用的时间
    end

	if protype == 1 then

        local oldrecv = sett.recv_i
        local curecv = tonumber(field[3])

        sett.from = from
        sett.recv_i = curecv

        if (oldrecv ~= 0) and (curecv > oldrecv) and (curecv - oldrecv) > 1  then
            sett.error  = sett.error + 1
        end

        if oldrecv == 0 then
            sett.pre_check_time  = curecv
        end

        if  (sett.recv_i -  sett.pre_check_time) > 2880 then
            sett.pre_check_time = sett.recv_i
            sett.error = 0
        end

        skynet.error("recv_data 1:", field[2], sett.pre_check_time ,  sett.error, oldrecv, sett.recv_i)

        --记住一个最后测试用的设备,用于测试用
        testset = field[2]

        sett.last_recvtime = os.time()

		return "1:"..tostring(field[3])

	elseif protype == 2 then

        if sett == nil then
            skynet.error("fail: recv_data2, but not find the set sn:", field[2])
            return nil
        end

		if tonumber(field[4]) ~= sett.send_i and sett.send_i ~= 0 then
			skynet.error("fail: recv_data not send_index:"..field[4].." :cu send index:"..sett.send_i, field[2])
            return nil
		end

        sett.recv_send_i = sett.send_i

        skynet.error("succeed:recv send data index = "..tonumber(field[4]), field[2])

        return nil
	end

	return nil
end

local function get_state(sn)
    local sett = g_set[testset]
    if sett == nil then
        skynet.error("get_state warring: not find set ",sn)
        return 0
    end

    local cu_time = os.time()
    if (cu_time - sett.last_recvtime ) > 120  then
        skynet.error("get_state warring: the set drop max packet", cu_time - sett.last_recvtime, sn)
        return 1
    end

    if cu_time  < sett.last_ready_time then
        skynet.error("get_state warring: the set is using ", sn)
        return 3
    end

    return 2
end

local function send_data(sn, times)
    local sett = g_set[testset]
    if sett == nil then
        skynet.error("send_data warring: not find set ",sn)
        return 0
    end

    local cu_time = os.time()
    if (cu_time - sett.last_recvtime ) > 120 then
        skynet.error("send_data warring: the set drop max packet", cu_time - sett.last_recvtime, sn)
        return 1
    end

    if cu_time  < sett.last_ready_time then
        skynet.error("send_data warring: the set is using ", sn)
        return 3
    end

    if (times > 3600*3) then
        skynet.error("send_data warring: the time error ",times, sn)
        return 4
    end

    sett.send_i = sett.send_i + 1 

    local str = string.format("2:%d:%d:%d",1,1,times)

    socket.sendto(l_host, sett.from, str)

    skynet.error("send_data: ", str, sn)

    local recv_num = 25 
    while recv_num > 0 do
        if sett.recv_send_i ~= sett.send_i then
            recv_num = recv_num - 1
            skynet.sleep(200)
        end
    end

    if recv_num > 0 then
        skynet.error("send_data warring: the set time out",  sn)
        return 1
    end

    skynet.error("send_data: recv ok ", str, sn)
    return 2
end

local function time_on()
    while(true) do
        if l_host and testset then

            local sett = g_set[testset]

            sett.send_i = sett.send_i + 1 
        	local str = string.format("2:%d:%d:%d", sett.send_i ,1,1,3000)
        	if l_on == 0 then
        		str = string.format("2:%d:%d:%d", sett.send_i ,1,0,3000)
        		l_on = 1
        	else
        		l_on = 0
        	end

		    socket.sendto(l_host, l_from, str)
          
        end
        skynet.sleep(30*60*100)
        --skynet.sleep(5*100)
    end
end

local function server()
	l_host = socket.udp(function(str, from)
		skynet.error("server recv:"..str.."    addr="..socket.udp_address(from))

        l_from = from
        local ret = recv_data(str, from)
        if ret then
		    socket.sendto(l_host, from, ret)
	    end

        index = index + 1
	end , "0.0.0.0", 8765)	-- bind an address
end

--[[
in:
{
    number:2                         --请求数组个数
    setsn:["2323323","2323323"]
}

out:
{       
    number:2 ,                       --返回数组个数
    setsn:[2,3]                      --对应状态值   
                                     0：没有这个设备，   
                                     1：在线 最近24小时内但是偶丢包，连接不稳定，这个需要检查其天线的原因
                                     2：在线 最近24小时内非常稳定，无丢包现像，并准备好使用
                                     3：在线 正在使用中
}
--]]

function command.getstate(injson)

    local ok, jsonobj  = pcall(cjson.decode, injson)
    if not ok then
        skynet.error("cjson.decode not ok : "..injson)
        return "{error:0}"
    end

    print_t.print(jsonobj, 10)

    local list_num = tonumber(jsonobj.number)

    skynet.error("number = ", list_num)

    local stata_t = {}

    for i = 1, list_num do 
        local ret = get_state(jsonobj.setsn[i])
        table.insert(stata_t, ret)
    end

    local ret_t = {}

    ret_t.number = list_num
    ret_t.setsn  = stata_t

    local ok, jsonstr  = pcall(cjson.encode, ret_t)
    if not ok then
        skynet.error("cjson.decode not ok : "..injson)
    end

    return jsonstr
end

--[[
in:
{
    "setsn": "333333333333333333333333",
    "playtime": 300
}

out:
{
    setsn:"222323"                   --返回数组个数
    state: 1                         --硬件执行结果   1: 正常执行   2:设备正使用中，现在不能执行   3：设备故障中，不能使用
}
--]]
function command.runset(injson)

    local ok, jsonobj  = pcall(cjson.decode, injson)
    if not ok then
        skynet.error("cjson.decode not ok : "..injson)
    end

    local ret = send_data(jsonobj.setsn, jsonobj.playtime)

    return string.format("{ setsn:%s, state:%d}", jsonobj.setsn, ret)
end


function test_recv_data(s, from)
    local field = string_split(s)

    skynet.error("test_recv_data:",field[1],field[2],field[3],field[4])

    local protype = tonumber(field[1])

    if protype == 1 then

        skynet.error("test recv_data 1:", field[2])
       
        return nil

    elseif protype == 2 then

        local str = string.format("2:%s:%s:%s:%0.2d:%0.2d", field[2],field[3],field[4],1,2);

        skynet.error("test succeed:recv send data index = "..tonumber(field[4]), field[2])

        return str
    end

    return nil
end

function OnTimerFunction()
    skynet.fork(function()

        c_socket = socket.udp(function(str, from)
            skynet.error("client recv", str, socket.udp_address(from))

            local ret = test_recv_data(str)
            if ret then
                socket.sendto(c_socket, from, ret)
                skynet.error("test send ", ret)
            end
        end)
        
        socket.udp_connect(c_socket, "127.0.0.1", 8765)

        local i = 1
        while true do
            
            socket.write(c_socket, string.format("1:333333333333333333333333:%d:200:2:2", i))  
            skynet.sleep(5*100)   
            i = i + 1
        end
    end)
end

function init_set()

    recv_data("1:333333333333333333333333:10:200:2:2", 200)
    
    recv_data("1:433333333333333333333333:10:200:2:2", 200)

    recv_data("1:533333333333333333333333:10:200:2:2", 200)

    recv_data("2:533333333333333333333333:10:200:2:2", 200)

end


skynet.start(function()
    skynet.register(".switchser")
    skynet.dispatch("lua", function(session, address, cmd, ...)
        local f = command[cmd]
        if f then
            skynet.ret(skynet.pack(f(...)))
        else
            error(string.format("Unknown command %s", cmd))
        end
    end)

    --init_set()

	skynet.fork(server)

    OnTimerFunction()

	--skynet.fork(time_on)
end)
